package 尚硅谷;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/*
 * 1、验证Volatile的可见性
 *   1.1、假设int number=0;，number变量之前根本没有添加Volatile关键字--没有可见性：main线程则不会知道上一个线程已经改变且将结果写回到主内存中了，导致其等待到上一个线程结束才会结束。
 *   1.2、number上加上Volatile--有可见性,及时通知其他线程主内存中的变量值已改变
 *
 * 2、验证Volatile不保证原子性
 *   若保证原子性，20个线程每个++1000次，最终结果为20000
 *   但Volatile不保证原子性，可以使用synchronized
 *
 * 3、验证
 * */


class MyData{
    volatile int number=0;

    public  void addT060(){
        this.number=60;
    }

    //此时number前面加了Volatile
    public void addPlus(){
        number++;
    }

    //保证原子性
    AtomicInteger atomicInteger=new AtomicInteger();
    public void addMyAtomic(){
        atomicInteger.getAndIncrement();//原子性的增加1
    }
}

public class VolatileDema {
    public static void main(String[] args)  {
        MyData myData=new MyData();
        for (int i = 1; i <= 20; i++) {
            new Thread(()->{
                for (int j = 0; j < 1000; j++) {
                    myData.addPlus();
                    myData.addMyAtomic();
                }
            },String.valueOf(i)).start();
        }
        //需要等待上面20个线程运行结束后再使用main线程获取最终的结果
        while (Thread.activeCount()>2){
            //当当前只有mian和后台GC线程外其他线程都结束了
            Thread.yield();
        }
        System.out.println(Thread.currentThread().getName()+"\t int type finally number value:"+myData.number);
        System.out.println(Thread.currentThread().getName()+"\t Atomic Type finally number value:"+myData.atomicInteger);
    }
    public static void seeOkByVolatile(){
        MyData myData=new MyData();
        new Thread(()->{
            System.out.println(Thread.currentThread().getName()+"\t come in");
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            myData.addT060();
            System.out.println(Thread.currentThread().getName()+"\t updated number value:"+myData.number);
        },"AAA").start();

        //第二个线程main
        while (myData.number==0){
            //第二个线程一直等待直到number改变
        }
        System.out.println(Thread.currentThread().getName()+"\t mission is over，main get number value:"+myData.number);
    }
}
